package br.com.programacao.concorrente.main;

import br.com.programacao.concorrente.problema.Buffer;
import br.com.programacao.concorrente.auxiliar.Constantes;
import br.com.programacao.concorrente.problema.Consumidor;
import br.com.programacao.concorrente.auxiliar.Log;
import br.com.programacao.concorrente.problema.Produtor;
import br.com.programacao.concorrente.monitor.Tela;
import br.com.programacao.concorrente.monitor.MonitorConsumer;
import java.util.concurrent.Semaphore;
import javax.swing.JOptionPane;

/**
 * Classe principal da Etapa1 do ATPS de programação concorrente
 */
public class Main {

    /**
     * Metodo principal. Inicio da Execução
     *
     * @param args the command line arguments
     */
    private static Semaphore sem;
    private static Semaphore mutex;

    public static void main(String[] args) {
        Consumidor consumer;
        Produtor producer;
        Thread t;
        Thread p;
        MonitorConsumer monitor;
        Tela tela;
        

        try {
            Constantes.NUMBER_EXECUTION = Integer.parseInt(JOptionPane.showInputDialog("Informe o numero da execucao"));
            Constantes.QTD_THREADS = Integer.parseInt(JOptionPane.showInputDialog("Informe a quantidade de Threads"));
            //Pega a instancia do buffer.
            Buffer buffer = Buffer.getInstance();
            
            //Intancia os semaforos que serão utilizados na aplicação
            sem = new Semaphore(0);
            //instancia o semaforo mutex com a quantidade de threads que serão utilizadas
            mutex = new Semaphore(Constantes.QTD_THREADS);
            //pega o instante que iniciou a execução do programa
            Constantes.INSTANT_INIT = Constantes.getTimeMillis();
            if (buffer != null) {
                //instancia o frame de monitoração da execução das trheads
                tela = new Tela(buffer);
                tela.setVisible(true);

                //iniciar a thread de monitoramento. 
                monitor = new MonitorConsumer(tela);
                monitor.init();

                //loop para criar a iniciar todas as threads testadas de produção
                for (int i = 1; i <= Constantes.QTD_THREADS; i++) {
                    producer = new Produtor(buffer, Constantes.NUMBER_EXECUTION,sem,mutex);
                    p = new Thread(producer, String.valueOf(i));
                    p.start();
                }
                
                // pausa para as Threads produtoras começarem a iniciar
                Thread.sleep(1000L);
                
                //loop para criar a iniciar todas as threads testadas de consumo
                for (int i = 1; i <= Constantes.QTD_THREADS; i++) {
                    consumer = new Consumidor(buffer, Constantes.NUMBER_EXECUTION,sem,mutex);
                    t = new Thread(consumer, String.valueOf(i));
                    t.start();
                }
            } else {
                //Lança a execeção caso o buffer não seja instanciado.
                throw new Exception("Buffer está nulo");
            }
        } catch (Exception e) {
            Log.getLogger(Main.class).error(e);
        }
    }
}
